﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace PocketBook.Model
{
    [Serializable]
    public sealed class Book : IXmlSerializable
    {
        public const int TotalPages = 8;

        public static Func<IDesign> DefaultDesign;

        public Book()
        {
            Pages = Enumerable.Range(0, TotalPages).Select(n => DefaultDesign()).ToArray();
        }

        public Book(IEnumerable<IDesign> setOfPageDesigns)
        {
            if (setOfPageDesigns.Count() != TotalPages) throw new ArgumentException("setOfPageDesigns");
            Pages = setOfPageDesigns.ToArray();
        }

        public IDesign this[int page]
        {
            get { return Pages[page]; }
            set { Pages[page] = value; }
        }

        public IDesign[] Pages { get; private set; }

        // Top-to-bottom, left-to-right of printed page. Rotation alternates between -90 and +90.
        public IEnumerable<IDesign> FoldablePrintingSequence
        {
            get { return new[] {7, 1, 6, 0, 5, 2, 4, 3}.Select(n => Pages[n]); }
        }

        XmlSchema IXmlSerializable.GetSchema()
        {
            return null;
        }

        void IXmlSerializable.ReadXml(XmlReader reader)
        {
            if (!reader.ReadToFollowing("Page")) return;

            for (var i = 0; i < TotalPages; ++i)
            {
                var type = reader.GetAttribute("type");

                // ReSharper disable AssignNullToNotNullAttribute
                var design = (IDesign) Activator.CreateInstance(Type.GetType(type));
                // ReSharper restore AssignNullToNotNullAttribute
                Pages[i] = design;

                var serializableDesign = design as IXmlSerializable;

                if (serializableDesign != null)
                {
                    using (var stateReader = reader.ReadSubtree())
                        serializableDesign.ReadXml(stateReader);
                }

                if (! reader.ReadToNextSibling("Page")) break;
            }
        }

        void IXmlSerializable.WriteXml(XmlWriter writer)
        {
            foreach (var page in Pages)
            {
                writer.WriteStartElement("Page");

                var type = page.GetType().AssemblyQualifiedName;
                writer.WriteAttributeString("type", type);

                var serializableDesign = page as IXmlSerializable;
                if (serializableDesign != null)
                    serializableDesign.WriteXml(writer);

                writer.WriteEndElement();
            }
        }        
    }
}